package com.wenshi.web.netty.handler;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wenshi.common.constant.ModbusConstants;
import com.wenshi.common.core.domain.ModbusFrame;
import com.wenshi.common.utils.ByteBufUtils;
import com.wenshi.common.utils.ByteUtils;
import com.wenshi.common.utils.ChannelMap;
import com.wenshi.system.service.ISysDeviceService;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;

import static com.wenshi.system.init.InitMappingMap.*;


@Slf4j
@Component
@ChannelHandler.Sharable
public class ModbusClientHandler extends SimpleChannelInboundHandler<ModbusFrame> {

    private Throwable lastException;
    @Autowired
    private ISysDeviceService sysDeviceService;

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("active channel={}", ctx.channel(), "id=", ctx.channel().id().asShortText());
        InetSocketAddress socket = (InetSocketAddress) ctx.channel().remoteAddress();
        String hostAddress = socket.getAddress().getHostAddress();
        ChannelMap.getChannelMap().put(hostAddress, ctx.channel());
//        int transactionId = 0; // 事务标识符，应根据实际情况设置
//        int protocolId = 0;
//        int length = 6; // Modbus请求的长度，此处以功能码03查询为例
//        int unitId = 1;
//        byte functionCode = 0x01; // 读持有寄存器的功能码
//        byte startAddress = 0x00; // 起始地址
//        byte quantityOfRegisters = 0x02; // 查询寄存器的数量
//
//        ByteBuf data = ctx.alloc().buffer();
////        data.writeByte(unitId);
////        data.writeByte(functionCode);
//        data.writeShort(startAddress);
//        data.writeShort(quantityOfRegisters);
//
//        ModbusFrame requestFrame = new ModbusFrame(transactionId, protocolId, length, unitId, functionCode, data);
//
//        // 在此，我们应将ModbusFrame封装成ByteBuf发送出去，而不是直接发送ModbusFrame对象
////        ByteBuf frame = ctx.alloc().buffer();
////        frame.writeShort(requestFrame.getTransactionId());
////        frame.writeShort(requestFrame.getProtocolId());
////        frame.writeShort(requestFrame.getLength());
////        frame.writeByte(requestFrame.getUnitId());
////        frame.writeByte(requestFrame.getFunctionCode());
////        frame.writeBytes(requestFrame.getData());  // 注意：此处假设getData直接返回ByteBuf
////
//        ctx.writeAndFlush(requestFrame);
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ModbusFrame frame) throws Exception {

        // 获取基本信息
        int transactionId = frame.getTransactionId();
        int protocolId = frame.getProtocolId();
        int length = frame.getLength(); // 包括单元标识和数据的长度
        int unitId = frame.getUnitId();
        byte functionCode = frame.getFunctionCode();
        ByteBuf data = frame.getData();
        InetSocketAddress socket = (InetSocketAddress) ctx.channel().remoteAddress();
        String hostAddress = socket.getAddress().getHostAddress();
        if (protocolId != 0) {
            log.info("Error: Invalid Protocol ID.");
            return;
        }
        log.info("Transaction ID: " + transactionId);
        // 检查是否为异常响应（功能码高于0x80）
        if ((functionCode & 0xFF) >= 0x80) {
            // 确保数据部分至少有1字节长度用于异常代码
            if (data != null && data.readableBytes() >= 1) {
                byte exceptionCode = data.readByte();
                log.info("Exception Response Received,Exception Function Code:{},Exception Code:{}",functionCode,(exceptionCode & 0xFF));
                // 根据异常代码进行具体处理
                handleException(frame, exceptionCode);
            } else {
                log.info("Error: Invalid exception response length.");
            }
        } else {
            // 对于正常响应，处理后续数据
            if (data != null) {
//                byte[] responseData = new byte[data.readableBytes()];
//                data.readBytes(responseData);
                log.info("Success Response Received,Function Code:{} ", (functionCode & 0xFF));
                // 处理成功响应的数据
                handleSuccessResponse(frame, data,hostAddress,transactionId);
            } else {
                log.info("No Data in Response.");
            }

        }
    }

    private void handleException(ModbusFrame frame, byte exceptionCode) {
        // 根据不同的exceptionCode处理异常情况
        switch (exceptionCode) {
            case 1:
                log.info("Exception: Illegal Function");
                break;
            case 2:
                log.info("Exception: Illegal Data Address");
                break;
            // 根据需要添加更多的异常处理逻辑
            default:
                log.info("Unknown exception for function Code: " + frame.getFunctionCode());
                break;
        }
        // 可能会需要通知相关代码异常发生，或进行重试等操作
    }

    private void handleSuccessResponse(ModbusFrame frame, ByteBuf data, String hostAddress,Integer transactionId) {
        // 对数据进行处理可能会涉及数据解码、交给业务层处理等
        int transactionId1 = frame.getTransactionId();
        //获取发送的modbus请求，读取其中的起始地址和查询数量
        ModbusFrame modbusFrame = integerModbusFrameMap.get(transactionId1);

        ByteBuf requestData = modbusFrame.getData();
        requestData.readerIndex(0);
        //起始地址
        byte[] bytes2 = ByteBufUtils.parseTwo(requestData);
        String s = ByteUtils.byteArrayToHexStr(bytes2);
        Integer startAd = Integer.parseInt(s, 16);

        //读取数量/寄存器 or 线圈
        byte[] bytes = ByteBufUtils.parseTwo(requestData);
        String bytesToString = ByteUtils.byteArrayToHexStr(bytes);
        Integer size = Integer.parseInt(bytesToString, 16);
        // 解析和处理数据，根据functionCode的不同处理不同的业务逻辑
        byte functionCode = frame.getFunctionCode();
        switch (functionCode) {
            case ModbusConstants.READ_COILS: // 读保持寄存器
                // 解析responseData中的注册数据
                handleReadCoilsAndDiscrete(startAd, size, data);
                log.info("Read Coils Response.");
                break;
            case ModbusConstants.READ_DISCRETE_INPUTS: // 读保持寄存器
                // 解析responseData中的注册数据
                handleReadCoilsAndDiscrete(startAd, size, data);
                log.info("Read Discrete Inputs Response.");
                break;
            case ModbusConstants.READ_HOLDING_REGISTERS: // 读保持寄存器
                // 解析responseData中的注册数据
                handleReadHoldingRegisters(startAd, size, data);
                log.info("Read Holding Registers Response.");
                break;
            case 0x04: // 读保持寄存器
                // 解析responseData中的注册数据
                log.info("Read ReadInputRegisters Response.");
                break;
            case 0x05: // 写单个线圈
                // 解析responseData中的注册数据
                log.info("Write Single Coil Response.");
                break;
            case 0x06: // 写单个寄存器
                // 解析responseData中的注册数据
                log.info("Write Single Registers Response.");
                break;
            case 0x0F: // 写多个线圈
                // 解析responseData中的注册数据
                log.info("Write Multiple Coil Response.");
                break;
            case 0x10: // 写多个寄存器
                // 解析responseData中的注册数据
                log.info("Write Multiple Registers Response.");
                break;
            // 根据需要添加更多的处理逻辑
            default:
                log.info("Unhandled function code: " + (functionCode & 0xFF));
                break;
        }
//        if (functionCode== ModbusConstants.READ_COILS||functionCode==ModbusConstants.READ_DISCRETE_INPUTS){
//            extracted1(startAd, size, data);
//        }
//        if (functionCode== ModbusConstants.READ_HOLDING_REGISTERS){
//            log.info("Read Holding Registers Response.");
//            extracted(startAd, size, data);
//        }

        for (Map.Entry<Integer, Optional<Integer>> integerStringEntry : modbusAndResultMap.entrySet()) {
            Integer key = integerStringEntry.getKey();
            Optional<String> optionalKey = modbusAndNameMap.get(key);
            if (optionalKey==null){
                continue;
            }
//            String descValue = modbusAndNameMap.get(key);
            Optional<Integer> optionalValue = integerStringEntry.getValue();
            if (!optionalKey.isPresent()) {
                // 处理空值
                continue;
            } else {
                String actualValue = optionalKey.get();
                if (!optionalValue.isPresent()){
//                    log.info("{}",actualValue);
                    // 处理空值
                    continue;
                }
                Integer resultValue = optionalValue.get();
                nameAndResultMap.put(actualValue, resultValue);
            }
//            sysDeviceService.getByDeviceIp(hostAddress);
            resultAndDescMap.put(hostAddress, nameAndResultMap);
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                String writeValueAsString = objectMapper.writeValueAsString(nameAndResultMap);

//                System.out.println(writeValueAsString);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }

        }
        // 根据事务ID找到之前关联的CompletableFuture
        CompletableFuture<Boolean> future = pendingRequests.remove(transactionId1);

        if (future != null) {
            try {
                // 解析响应数据
//                Map<String, Integer> result = parseResponse(response);

//                 使用解析的结果完成CompletableFuture
                future.complete(true);
            } catch (Exception e) {
                // 如果解析出现错误，异常地完成CompletableFuture
                future.completeExceptionally(e);
            }
        } else {
            // 没有找到对应的CompletableFuture，可能是超时或其他原因
        }
    }
    private static void handleReadCoilsAndDiscrete(Integer startAd, Integer size, ByteBuf data) {
        byte[] bytes1 = ByteBufUtils.parseOne(data);
        String bytesToString1 = ByteUtils.byteArrayToHexStr(bytes1);
        //获取线圈状态数据的数量
        Integer parseShortI = Integer.parseInt(bytesToString1, 16);
        //获取每个字节需要读取的长度,向上取整
        int number= (int) Math.ceil((double) size /parseShortI);
        for (int j=1;j<=parseShortI;j++){
            byte[] bytes3 = ByteBufUtils.parseOne(data);
            //获得8位的bit
            char[] chars = ByteUtils.bytesToChars(bytes3);
            for (int i=0;i<number;i++){
                char aChar = chars[chars.length-1-i];
                //每个线圈代表的值
                String value = String.valueOf(aChar);
                //计算当前线圈的地址
                int currentAddress = startAd + (j - 1) * number + i;
                // 将当前线圈的状态放入映射中
                // 检查currentAddress是否在范围之内
                if (currentAddress >= startAd && currentAddress <= startAd + size) {
                    // 将当前线圈的状态放入映射中
                modbusAndResultMap.put(currentAddress, Optional.of(Integer.valueOf(value)));
            }
        }
    }
    }

    private static void handleReadHoldingRegisters(Integer startAd, Integer size, ByteBuf data) {
        byte[] resultLength = ByteBufUtils.parseOne(data);
        String bytesStr = ByteUtils.byteArrayToHexStr(resultLength);
        Integer parseIntLength = Integer.parseInt(bytesStr, 16);
        //浮点型数据
        if (parseIntLength==4){
            byte[] bytes = ByteBufUtils.parseByteCount(data, 4);
            float aFloat = ByteBuffer.wrap(bytes).getFloat();
            int result = (int) (aFloat * 1000);
            modbusAndResultMap.put(startAd, Optional.of(result));
        }else {
            for (int i = startAd; i < startAd + size; i++) {
                //每个点位对应的数据
                byte[] bytes3 = ByteBufUtils.parseTwo(data);
                String bytesToString3 = ByteUtils.byteArrayToHexStr(bytes3);
                Integer parseShortI = Integer.parseInt(bytesToString3, 16);
                modbusAndResultMap.put(i, Optional.of(parseShortI));
            }
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelInactive();
        InetSocketAddress socket = (InetSocketAddress) ctx.channel().remoteAddress();
        String hostAddress = socket.getAddress().getHostAddress();
        sysDeviceService.updateDeviceByIp(hostAddress,Boolean.FALSE);
        if(lastException != null) {
            log.info("已断开:{}",lastException.toString());
            // Handle based on lastException
        } else {
            // Handle normal disconnection
            log.info("已断开:{}",hostAddress);
        }
        // ... other clean up code
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        // Log the exception
        cause.printStackTrace();

        // Save the exception to analyze later
        this.lastException = cause;

        // Close the connection when an exception is raised.
        ctx.close();
    }
}